#pragma once
#include <iostream>
#include <google/protobuf/map.h>
#include <vector>
#include <string>
#include "../mqcommon/Helper.hpp"
#include "../mqcommon/Log.hpp"
#include "../mqcommon/msg.pb.h"
using namespace std;
namespace mq
{
    class MsgQueue
    {
    public:
        using MsgQueuePtr = shared_ptr<MsgQueue>;
        string _name;
        bool _durable;
        bool _exclusive;
        bool _auto_delete;
        google::protobuf::Map<string, string> _args;
        MsgQueue() {}
        MsgQueue(const string &name, bool durable, bool exclusive, bool auto_delete, const google::protobuf::Map<string, string> &args)
            : _name(name), _durable(durable), _exclusive(exclusive), _auto_delete(auto_delete), _args(args)
        {
        }
        void setArgs(const string &str)
        {
            vector<string> arry;
            mq::StringHelper::splite(str, "&", arry);
            for (auto &s : arry)
            {
                size_t pos = s.find("=");
                if (pos == string::npos)
                {
                    DLOG("字符串解析出错");
                    continue;
                }
                string key = s.substr(0, pos);
                string val = s.substr(pos + 1);
                _args[key] = val;
            }
        }
        string getArgs()
        {
            string ret;
            for (auto &it : _args)
            {
                ret += (it.first + "=" + it.second + "&");
            }
            return ret;
        }
    };
    class MsgQueueMapper
    {
    public:
        using QueueMap = unordered_map<string, MsgQueue::MsgQueuePtr>;
        MsgQueueMapper(const string &dbname) : _sql_helper(dbname)
        {
            string dir = mq::FileHelper::parentDirectory(dbname);
            mq::FileHelper::createDirectory(dir);
            assert(_sql_helper.open());
            createTable();
        }
        ~MsgQueueMapper()
        {
            _sql_helper.close();
        }
        // 创建队列表
        void createTable()
        {
            string sql = "create table if not exists queue_table(\
            name varchar(32) primary key,\
            durable int,\
            exclusive int,\
            auto_delete int,\
            args varchar(128));";
            if (_sql_helper.exec(sql.c_str(), nullptr, nullptr) == false)
            {
                DLOG("数据库表创建失败");
                abort();
            }
        }
        // 删除队列表
        void removeTable()
        {
            string sql = "drop table queue_table;";
            if (_sql_helper.exec(sql, nullptr, nullptr) == false)
            {
                DLOG("数据库表删除失败");
                abort();
            }
        }
        // 向对列表中插入队列
        bool insert(MsgQueue::MsgQueuePtr &queue)
        {
            stringstream ss;
            ss << "insert into queue_table values(";
            ss << "'" << queue->_name << "',";
            ss << queue->_durable << ",";
            ss << queue->_exclusive << ",";
            ss << queue->_auto_delete << ",";
            ss << "'" << queue->getArgs() << "');";
            return _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        // 从列表中删除队列
        void remove(const std::string &name)
        {
            stringstream ss;
            ss << "delete from queue_table where name='" << name << "';";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        // 从可持久化文件恢复
        QueueMap recovery()
        {
            QueueMap result;
            string sql = "select name, durable, exclusive, auto_delete, args from queue_table";
            if (_sql_helper.exec(sql, selectCallback, &result) == false)
            {
                DLOG("数据库表查询失败");
                abort();
            }
            return result;
        }

    private:
        static int selectCallback(void *arg, int num, char **row, char **fields)
        {
            QueueMap *result = static_cast<QueueMap *>(arg);
            MsgQueue::MsgQueuePtr mqp = make_shared<MsgQueue>();
            mqp->_name = row[0];
            mqp->_durable = (bool)stoi(row[1]);
            mqp->_exclusive = (bool)stoi(row[2]);
            mqp->_auto_delete = (bool)stoi(row[3]);
            if (row[4])
                mqp->setArgs(row[4]);
            result->insert(make_pair(mqp->_name, mqp));
            return 0;
        }

    private:
        mq::SqliteHelper _sql_helper;
    };
    class MsgQueueManager
    {
    public:
        using MsgQueueManagerPtr = shared_ptr<MsgQueueManager>;
        using QueueMap = unordered_map<string, MsgQueue::MsgQueuePtr>;
        MsgQueueManager(const string &dbname) : _mapper(dbname)
        {
            _queues = _mapper.recovery();
        }
        // 新建一个队列
        bool declareQueue(const std::string &name, bool durable, bool exclusive, bool auto_delete, const google::protobuf::Map<string, string> &args)
        {
            unique_lock<mutex> lock(mutex);
            auto it = _queues.find(name);
            if (it != _queues.end())
                return true;
            auto mqp = make_shared<MsgQueue>();
            mqp->_name = name;
            mqp->_durable = durable;
            mqp->_exclusive = exclusive;
            mqp->_auto_delete = auto_delete;
            mqp->_args = args;
            if (durable == true)
            {
                if (_mapper.insert(mqp) == false)
                {
                    DLOG("队列声明/创建失败");
                    return false;
                }
            }
            _queues.insert(make_pair(name, mqp));
            return true;
        }
        // 删除指定队列
        void deleteQueue(const std::string &name)
        {
            unique_lock<mutex> lock(mutex);
            auto it = _queues.find(name);
            if (it == _queues.end())
                return;
            if (it->second->_durable == true)
                _mapper.remove(name);
            _queues.erase(name);
        }
        // 获取指定队列信息
        MsgQueue::MsgQueuePtr selectQueue(const std::string &name)
        {
            unique_lock<mutex> lock(mutex);
            auto it = _queues.find(name);
            if (it == _queues.end())
                return make_shared<MsgQueue>();
            return it->second;
        }
        // 获取所有队列信息
        QueueMap allQueues()
        {
            unique_lock<mutex> lock(mutex);
            return _queues;
        }
        // 判断指定队列是否存在
        bool exists(const std::string &name)
        {
            unique_lock<mutex> lock(mutex);
            auto it = _queues.find(name);
            if (it == _queues.end())
                return false;
            return true;
        }
        // 获取队列数量
        size_t size()
        {
            unique_lock<mutex> lock(mutex);
            return _queues.size();
        }
        // 清空管理中所有队列
        void clear()
        {
            unique_lock<mutex> lock(mutex);
            _mapper.removeTable();
            _queues.clear();
        }

    private:
        mutex _mutex;
        MsgQueueMapper _mapper; // 持久化操作句柄
        QueueMap _queues;       // 队列管理句柄
    };
}